package com.bsj.travel.mqtt.auth;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.bsj.travel.cached.redis.RedisCached;
import com.bsj.travel.config.rocketmq.producer.BaseMqPushUtil;
import com.bsj.travel.constant.ActConstants;
import com.bsj.travel.constant.BaseServerTopicConstants;
import com.bsj.travel.constant.NumericalConstants;
import com.bsj.travel.def.common.DTO.mqtt.EventAct;
import com.bsj.travel.def.common.DTO.mqtt.MqttEvent;
import com.bsj.travel.def.common.DTO.mqtt.NetworkEnum;
import com.bsj.travel.def.mqtt.auth.MqttSignature;
import com.bsj.travel.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.iot.mqtt.codec.MqttQoS;
import net.dreamlu.iot.mqtt.core.server.auth.IMqttServerSubscribeValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.tio.core.ChannelContext;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * @author yinhao
 * @version 1.0
 * @description 客户端主题订阅校验，可自行进行业务扩展
 * @date 2023/11/7
 */
@Slf4j
public class MqttSubscribeValidator implements IMqttServerSubscribeValidator {

    @Autowired
    private BaseMqPushUtil baseMqPushUtil;

    @Autowired
    private RedisCached redisCached;

    /**
     * 获取基础通讯topic
     */
    private static Set<String> baseTopic;


    @Override
    public boolean isValid(ChannelContext channelContext, String clientId, String topic, MqttQoS qoS) {
        long millis = System.currentTimeMillis();
        // 校验客户端订阅的topic，校验成功返回true，失败返回false
        MqttSignature mqttAuth = new MqttSignature(clientId);
        var productKey = mqttAuth.getProductKey();
        var deviceName = mqttAuth.getDeviceName();
        // 替换主题中的产品设备信息,还原topicClass
        String topicClass = StringUtils.reductionTopicClass(topic, productKey, deviceName);
        // 获取该产品信息的topicClass,进行判断是否有权限
        if (checkTopicClass(productKey, topicClass)) {
            return true;
        } else {
            log.error("MqttSubscribeValidator.hasPermission，产品信息获取失败,无法订阅。clientId:{}, productKey:{}", clientId, productKey);
            MqttEvent<String> mqttEvent = new MqttEvent<>();
            mqttEvent.setClient(mqttAuth.getDeviceName() + "&" + mqttAuth.getProductKey());
            mqttEvent.setTopic(topic);
            mqttEvent.setQos(qoS.value());
            mqttEvent.setTimestamp(millis);
            mqttEvent.setData(topic);
            EventAct eventAct = EventAct.builder()
                    .timestamp(millis)
                    .traceId(RandomUtil.randomString(30))
                    .serveType(2)
                    .operate(ActConstants.SUB)
                    .event(mqttEvent)
                    .build();
            //订阅权限异常,记录日志
            eventAct.setCode(NetworkEnum.MQTT_SUB_FAIL.getCode());
            baseMqPushUtil.sendTopicBytes(BaseServerTopicConstants.TRAVEL_MQTT_MSG_PROCESS_TOPIC,
                    BaseServerTopicConstants.TRAVEL_MQTT_MSG_PROCESS_BEHAVIOR_TAG, JSON.toJSONBytes(eventAct));
            return false;
        }
    }

    /**
     * 判断是否有权限
     *
     * @param productKey 产品key
     * @return
     */
    private boolean checkTopicClass(String productKey, String topicClass) {
        // 为空则初始化
        if (baseTopic == null) {
            Set<String> baseTopicList = redisCached.getBaseTopicClassSet(NumericalConstants.TWO);
            baseTopic = Objects.requireNonNullElseGet(baseTopicList, HashSet::new);
        }
        // 先判断获取基础通讯topic,优先判断基础通讯，直接命中内存中缓存，提高性能
        if (baseTopic.contains(topicClass)) {
            return true;
        } else {
            // 根据productKey，从缓存中获取topicClass，过滤权限为发布
            Set<String> topicClassSet = redisCached.getTopicClassSet(productKey, NumericalConstants.TWO);
            return topicClassSet.contains(topicClass);
        }
    }
}
